home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
kernel
/
rs232.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
21KB
|
715 lines
#include "kernel.h"
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include <sgtty.h>
#include "proc.h"
#include "tty.h"
#if (CHIP == M68000)
#include "staddr.h"
#include "stmfp.h"
#endif
/* Definitions used by the RS232 driver. */
#define RS_BUF_SIZE 256 /* output buffer per serial line */
#define SPARE 16 /* leave room in buffer for echoes */
#define THRESHOLD 20 /* # chars to accumulate before msg */
#if (CHIP != M68000)
#define PRIMARY 0x3F8 /* I/O port of primary RS232 */
#define SECONDARY 0x2F8 /* I/O port of secondary RS232 */
/* Constants relating to the 8250. */
#define RS232_RATE_DIVISOR 0 /* address of baud rate divisor reg */
#define RS232_TRANSMIT_HOLDING 0 /* address of transmitter holding reg*/
#define RS232_RECEIVER_DATA_REG 0 /* address of receiver data register */
#define RS232_INTERRUPTS 1 /* address of interrupt enable reg */
#define RS232_INTERRUPT_ID_REG 2 /* address of interrupt id register */
#define RS232_LINE_CONTROL 3 /* address of line control register */
#define RS232_MODEM_CONTROL 4 /* address of modem control register */
#define RS232_LINE_STATUS 5 /* address of line status register */
#define RS232_MODEM_STATUS 6 /* address of modem status register */
#define LINE_CONTROLS 0x0B /* odd parity,1 stop bit,8 data bits */
#define MODEM_CONTROLS 0x0B /* RTS & DTR */
#define ADDRESS_DIVISOR 0x80 /* value to address divisor */
#define HOLDING_REG_EMPTY 0x20 /* transmitter holding reg empty */
#define RS232_INTERRUPT_CLASSES 0x03 /* receiver Data Ready & xmt empty */
#define UART_FREQ 115200L /* UART timer frequency */
#endif
#define DEF_BAUD 1200 /* default baud rate */
/* Line control setting related constants. */
#define ODD 0
#define EVEN 1
#define NONE -1
#define PARITY_TYPE_SHIFT 4 /* shift count for parity_type bit */
#define STOP_BITS_SHIFT 2 /* shift count for # stop_bits */
#define DATA_LEN 8 /* how much to shift sg_mode for len */
#if (CHIP != M68000)
#define PARITY_ON_OFF 0x08 /* position of parity bit in line reg*/
/* RS232 interrupt types. */
#define MODEM_STATUS 0x00 /* UART modem status change */
#define TRANSMITTER_READY 0x02 /* transmitter ready to accept data */
#define RECEIVER_READY 0x04 /* data received interrupt */
#define LINE_STATUS 0x06 /* UART line status change */
#define INT_TYPE_MASK 0x06 /* mask to mask out interrupt type */
#define INT_PENDING 0x01 /* position of interrupt-pending bit */
/* Status register values. */
#define DATA_REGISTER_EMPTY 0x20 /* mask to see if data reg is empty */
#define DATA_RECEIVED 0x01 /* mask to see if data has arrived */
#endif
#if (CHIP == M68000)
#define SIAIN(c) (c) = MFP->mf_udr
#define SIAOUT(c) {lastchar = (c); MFP->mf_udr = lastchar;}
#endif
/* Global variables used by the RS232 driver. */
#if (CHIP != M68000)
PRIVATE int first_rs_write_int_seen = FALSE;
#endif
PRIVATE struct rs_struct{
int rs_base; /* 0x3F8 for primary, 0x2F8 secondary*/
/* unused on ST */
int rs_busy; /* line is idle or not */
int rs_left; /* # chars left in buffer to output */
char *rs_next; /* pointer to next char to output */
char rs_buf[RS_BUF_SIZE]; /* output buffer */
} rs_struct[NR_RS_LINES];
#if (CHIP == M68000)
PRIVATE int dummy; /* to read error chars in */
PRIVATE int lastchar; /* save last outputted char for retry */
PUBLIC void rs_flush();
PUBLIC void rs_out_char();
PUBLIC void rs_sig();
PUBLIC void init_rs232();
PUBLIC void set_uart();
PRIVATE void rs_read_int();
PRIVATE void rs_write_int();
PRIVATE void rs_feed();
PRIVATE void start_rs232();
PRIVATE void serial_out();
PRIVATE void rs_expand();
PRIVATE void config_rs232();
PUBLIC void
siaint(type)
int type; /* interrupt type */
{
register unsigned char code;
register struct tty_struct *tp;
int s = lock();
switch (type & 0x00FF)
{
case 0x00: /* receive buffer full */
rs_read_int(SERIAL1);
break;
case 0x01: /* receive error */
printf("sia: receive error: status=%x\r\n", MFP->mf_rsr);
MFP->mf_rsr &= R_ENA;
SIAIN(dummy); /* discard char in case of overrun */
break;
case 0x02: /* transmit buffer empty */
rs_write_int(SERIAL1);
break;
case 0x03: /* transmit error */
code = MFP->mf_tsr;
if (code & ~(T_ENA | T_UE | T_EMPTY))
{
printf("sia: transmit error: status=%x\r\n", code);
SIAOUT(lastchar); /* retry */
}
break;
}
restore(s);
}
#else
/*===========================================================================*
* rs232 *
*===========================================================================*/
PUBLIC void rs232(unit)
int unit; /* which unit caused the interrupt */
{
/* When an RS232 interrupt occurs, mpx88.s catches it and calls rs232().
* Because more than one interrupt condition can occur at the same
* time, the conditions are presented in the interrupt-identification
* register in priority order, we have to keep scanning until the
* interrupt-pending bit goes down. Only one communications port is really
* supported here because the other vector is used by the Ethernet.
*/
int interrupt_type, t, old_state, val;
struct rs_struct *rs;
old_state = lock();
rs = &rs_struct[unit - NR_CONS];
while (TRUE) {
port_in(rs->rs_base + RS232_INTERRUPT_ID_REG, &interrupt_type);
if ((interrupt_type & INT_PENDING) == 1) break; /* 1 = no interrupt */
t = interrupt_type & INT_TYPE_MASK;
switch(t) {
case RECEIVER_READY: /* a character has arrived */
rs_read_int(unit);
break;
case TRANSMITTER_READY: /* a character has been output */
rs_write_int(unit);
break;
case LINE_STATUS: /* line status event, (disabled) */
port_in(rs_struct[unit-1].rs_base + RS232_LINE_STATUS, &val);
printf("RS 232 line status event %x\n", val);
break;
case MODEM_STATUS: /* modem status event, (disabled) */
port_in(rs_struct[unit-1].rs_base + RS232_MODEM_STATUS, &val);
printf("RS 232 modem status event %x\n", val);
break;
}
}
restore(old_state);
}
#endif
/*===========================================================================*
* rs_read_int *
*===========================================================================*/
PRIVATE void rs_read_int(line)
int line;
{
int val, k, base;
base = rs_struct[line - NR_CONS].rs_base;
/* Fetch the character from the RS232 hardware. */
#if (CHIP == M68000)
SIAIN(val);
#else
port_in(base + RS232_RECEIVER_DATA_REG, &val);
#endif
/* Store the character in memory so the task can get at it later */
if ((k = tty_buf_count(tty_driver_buf)) < tty_buf_max(tty_driver_buf)) {
/* There is room to store this character, do it */
k = k + k; /* each entry contains two bytes */
tty_driver_buf[k + 4] = val; /* store the ascii code */
tty_driver_buf[k + 5] = line; /* tell wich line it came from */
tty_buf_count(tty_driver_buf)++; /* increment counter */
if (tty_buf_count(tty_driver_buf) < THRESHOLD) {
/* Don't send message. Just accumulate. Let clock do it. */
INT_CTL_ENABLE;
flush_flag++;
return;
}
rs_flush(); /* send TTY task a message */
} else {
/* Too many character have been buffered. Discard excess */
INT_CTL_ENABLE;
}
}
/*===========================================================================*
* rs_flush *
*===========================================================================*/
PUBLIC void rs_flush()
{
/* Flush the tty_driver_buf by sending a message to TTY. This procedure can
* be triggered locally, when a character arrives, or by the clock task.
*/
int s = lock();
/* Build and send the interrupt message */
flush_flag = 0;
if ((tty_buf_count(tty_driver_buf) == 0) && (output_done == 0)) return; /* nothing to flush */
interrupt(TTY); /* send a message to the tty task */
restore(s);
}
/*===========================================================================*
* rs_write_int *
*===========================================================================*/
PRI